home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-05-04 | 42.3 KB | 1,113 lines | [TEXT/MPS ] |
-
- @node Hacking Xconq, Glossary, Design Hints, Top
-
- @chapter Hacking Xconq
-
- Although @i{Xconq} and its GDL have considerable power and flexibility
- already built in,
- you may decide that you want to modify the @i{Xconq} program itself.
- You should know what you are doing;
- @i{Xconq} is designed to be modifiable, but it is not simple code.
- In the past, people have found it easy to make changes,
- but much harder to make them correctly!
-
- @i{Xconq} is designed to be portable to different types of user interfaces.
- It is based on a kernel-interface architecture, where the semantics of
- the game, as documented in the preceding chapters, is part of the kernel,
- while the main program and player interaction are specific to each system.
-
- @i{Xconq} is also designed to allow the addition of new AIs. The default
- @code{"mplayer"} AI, while it is flexible and will attempt to play any side
- in any game, does not have the depth that is often important to success
- in a game. Its position is that of a generic AI program that can learn to
- play any game, given only the rules; while such a program might figure out
- how to win at tic-tac-toe or checkers, it is not going to be particularly
- good at the subtleties of go or chess.
-
- The @i{Xconq} GDL is also extensible. This is useful when the basic GDL
- does not provide some feature that is essential to a game.
-
- @section Kernel
-
- The kernel is the part of @i{Xconq} shared by all interfaces.
- It does no I/O except to files or for debugging.
-
- Specifically, the kernel supplies the following functionality:
- @itemize
- @item
- Data structure initialization. (@code{init_data_structures})
-
- @item
- Game module loading and interpretation. (@code{load_game_module})
-
- @item
- Initial player/side setup. (@code{make_trial_assignments})
-
- @item
- Synthesis methods. (@code{run_synthesis_methods})
-
- @item
- Final player/side setup. (@code{make_assignments})
-
- @item
- Game execution. (@code{run_game})
-
- @item
- Implementations of unit actions. (@code{prep_*_action})
-
- @item
- AI players.
-
- @item
- Help Info (@code{get_help_text})
-
- @item
- Game saving and scorekeeping.
- @end itemize
-
- @subsection Configuration Options
-
- There are a small number of options available to alter aspects of
- the kernel. These are defined in @code{kernel/config.h}.
-
- [eventually describe all of them?]
-
- @subsection Porting the Kernel
-
- The kernel should be restricted to ANSI C, and should avoid or optionalize
- features not in ``traditional'' C, such like prototypes.
- Although the kernel uses stdio,
- it does not assume the presence of a console (stdin, stdout, stderr).
- For instance, a graphical interface can arrange to disable stdin entirely
- and direct stdout/stderr into a file (see the Mac interface sources
- for an example).
-
- You should be careful about memory consumption. In general, the kernel
- takes the attitude that if it was worth allocating, it's worth hanging
- onto; and so the program does not free much storage. Also, nearly all
- of the allocation happens during startup. Since a game may run for a
- very long time (thousands of turns perhaps), it is important not to
- run the risk of exhausting memory at a climactic moment in the game!
-
- Also, the kernel should not exit on its own. The only permissible
- times are when the internal state is so damaged that interface
- error-handling routines (see below) cannot be called safely.
- Such situations are rare. If you add something to the kernel
- and need to handle error situations, then you should call one
- of the interface's error-handling routines.
- There are distinct routines for problems during initializations
- vs problems while running, and both error and warning routines.
- Warning routines may return, so kernel code should be prepared
- to continue on, while error routines will never return.
-
- @subsection Writing New Synthesis Methods
-
- You can add new synthesis methods to @i{Xconq}.
- This may be necessary if an external program
- does not exist, is unsuitable, or the external program
- interface is not available.
- Synthesis methods should start out by testing whether or not to run,
- and should never assume that any other method has been run before or
- after, nor that any particular game module has been loaded.
- However, ``tricks'' are usually OK, such as setting a particular global
- variable in a particular module only, then having the synthesis method
- test whether that global is set.
- See the file @code{init.c} for further details.
-
- Synthesis methods that take longer than a second or two to execute
- should generate percent-done info for the interface to use,
- via the function @code{announce_progress}.
- Be aware that most methods will be O(n) or O(n*n) on the
- size of the world or the number of units,
- so they can take much longer to set up
- a large game than a small one.
- Players will often go overboard and start up giant games,
- so this happens frequently.
- Also, @i{Xconq} may be running on a much smaller and slower
- machine than what you're using now.
-
- @subsection Writing New Namers
-
- [describe hook and interface]
-
- @subsection Writing New AIs
-
- You can add new types of AIs to @i{Xconq}.
- You would do this to add different strategies as well as
- to add AIs that are programmed specifically for a single game or
- class of games. (This is useful because the generic AI does not
- always understand the appropriate strategy for each game.)
-
- You have to design the object that is the AI's ``mental state''.
- If your AI need only react to the immediate situation, then this
- object can be very simple, but in general you will need to design
- a fairly elaborate structure with a number of substructures.
- Since there may be several AIs in a single game, you should be
- careful about using globals, and since @i{Xconq} games may often
- run for a long time, you should be careful not to consume memory
- recklessly.
-
- @itemize
- @item
- Name.
- This is a string, such as @code{"mplayer"}.
- It may be displayed to players, so it should not be too cryptic.
-
- @item
- Validity function.
- This runs after modules are loaded, and during player/side
- setup, and decides whether it can be in the given game on the given side.
- [have a chain of fallback AIs, or blow off the game?]
-
- @item
- Game init function. This runs before displays are set up, just in case
- a display examines the AI's state.
-
- @item
- Turn init function. This runs after all the units get their acp and mp
- for the turn, but before anybody actually gets to move.
-
- @item
- Unit order function. This gets run to decide what the unit should do.
- Usually it should be allowed to follow its plan.
- [do separate fns for before and after plan execution?]
-
- @item
- Event reaction functions. [how many?]
-
- @end itemize
-
- Note that these functions have very few constraints, so you can write them
- to work together in various ways. For instance, an AI can decide whether
- to resign once/turn, once/action, or once for each 4 units it moves, every
- other turn.
-
- [describe default AI as illustrative example]
-
- @subsection Extending GDL
-
- GDL has been designed so as to be relatively easily extensible.
- I say ``relatively'' because although it is quite easy to define a new
- keyword or table, it is not always so easy to integrate the implementation
- code into the kernel correctly.
-
- Instead of actually changing GDL, you can experiment with an addition
- by using the @code{extensions} property of unit, material, and terrain types.
- In the code, you call @code{get_u_extension}, pass it the type, name
- of the property, and a default to return if the value was not given.
- In the game definition, the designer would say
- @code{(unit town (extensions (my-ext xxx)))}.
-
- [show examples for global, property, table, event, task]
-
- The file @code{gvar.def} defines all the global variables.
-
- The file @code{utype.def} defines all the unit type properties.
-
- From time to time, it may be worthwhile to extend unit objects.
- This should be rare, because games may have thousands of units,
- and each unit requires at least 100 bytes of storage already,
- so you should avoid making them any larger.
- Properties of an individual unit are scattered through @code{keyword.def}.
- Once the structure slot is added, you just need to add reading and
- writing of the value, using the @code{K_@var{xxx}} enum that was
- defined with the keyword. You should attempt to make a reasonable
- default and use it to avoid writing out the value, so as to save
- time when @i{Xconq} reads a game in.
-
- GDL symbols beginning with @code{zz-} should be reserved for the use
- of AI code. You may want to add some of these, either to serve as a
- convenient place for AIs to cache the results of their analyis of a
- game, or else as a way for game designers to add ``hints'' for AIs
- that know to look at them.
-
- @node Interface, Ideas, Kernel, Porting Xconq
-
- @section Interface
-
- The player interface is how actual players interact with the game.
- It need not be graphical or even particularly interactive,
- in fact it could even be a network server-style interface!
- However, this section will concentrate on the construction
- of interactive graphical interfaces.
-
- An interface is always compiled in, so it has complete access to the
- game state. However, if your version of @i{Xconq} has any networking
- support, the interface should not modify kernel structures directly,
- but should instead use kernel routines. The kernel routines will
- forward any state modifications to all other programs participating
- in a game, so that everybody's state remains consistent.
-
- A working interface must provide some level of capability in each
- of these areas:
-
- @itemize
- @item
- Main program.
- The interface includes the main application and any
- system-specific infrastructure, such as event handling.
-
- @item
- Interpretation of startup options.
- This includes choice of games, variants, and players.
-
- @item
- Display of game state.
- This includes both textual and graphical displays,
- both static and dynamic.
-
- @item
- Commands/gestures for unit tasks and actions,
- and for general state modifications.
-
- @item
- Display update in response to state changes.
-
- @item
- Realtime progress.
- Some game designs require the interface
- to support realtime.
-
- @item
- Error handling.
- @end itemize
-
- The file @code{skelconq.c} in the @code{kernel} directory is
- a good example of a minimum working interface.
-
- Don't let interfaces ever set kernel object values directly, always
- go through calls that can be ``siphoned'' for networking.
-
- @subsection Main Program
-
- The interface provides @code{main()} for @i{Xconq};
- this allows maximum flexibility in adapting to different environments.
- In a sense, the kernel is a large library that the
- interface calls to do game-related operations.
-
- There is a standard set of calls that need to be made during
- initialization. The set changes from time to time, so the
- following extract from @file{skelconq} should not be taken as
- definitive:
- @example
- init_library_path(NULL);
- clear_game_modules();
- init_data_structures();
- parse_command_line(argc, argv, general_options);
- load_all_modules();
- check_game_validity();
- parse_command_line(argc, argv, variant_options);
- set_variants_from_options();
- parse_command_line(argc, argv, player_options);
- set_players_from_options();
- parse_command_line(argc, argv, leftover_options);
- make_trial_assignments();
- calculate_globals();
- run_synth_methods();
- final_init();
- assign_players_to_sides();
- init_displays();
- init_signal_handlers();
- run_game(0);
- @end example
- Note that this sequence is only straight-through for a simple command
- line option program; if you have one or more game setup dialogs, then
- you choose which to call based on how the players have progressed
- through the dialogs. The decision points more-or-less correspond to
- the different @code{parse_command_line} calls in the example.
- You may also need to interleave some interface-specific calls;
- for instance, if you want to display side emblems in a player/side
- selection dialog, then you will need to arrange for the emblem images
- to be loaded and displayable, rather than doing it as part of opening
- displays.
-
- Once a game is underway, the interface is basically self-contained,
- needing only to call @code{run_game} periodically to keep the
- game moving along. @code{run_game} takes one argument which can
- be -1, 0, or 1. If 1, then one unit gets to do one action, then
- the routine returns. If 0, the calculations are gone through, but
- no units can act. If -1, then all possible units will move before
- @code{run_game} returns. This last case is not recommended for interactive
- programs, since moving all units in a large game may take a very long
- time; several minutes sometimes, and @code{run_game} may not necessarily
- call back to the interface very often.
-
- @subsection Startup Options
-
- Although there are many different ways to get a game started,
- you have three main categories of functionality to support:
- 1) selection of the game to play, 2) setting of variants, and
- 3) selection of players. For command-line-using programs,
- the file @code{cmdline.c} need only be linked in to provide
- all of this functionality. For graphical interfaces, you will
- need to design appropriate dialogs. This can be a lot of work,
- exacerbated by the fact that these dialogs will be the first
- things that new @i{Xconq} players see, and will therefore shape
- their opinions about the quality of the interface and of the game.
-
- [more detail about what has to be in dialogs?]
-
- Interface code should check all player specs, not proceed with initialization
- until these are all valid.
-
- Both standard and nonstandard variants should vanish from or be grayed out
- in dialog boxes if irrelevant to a selected game.
-
- @subsection Progress Indication
-
- Some synthesis methods are very slow, and become even
- slower when creating large games, so the kernel will announce a slow process,
- provide regular updates, and signal when the process is done. The interface
- should display this in some useful way. In general, progress should always
- be displayed, although one could postpone displaying anything until after
- the first progress update, calculate an estimated time to completion, and
- not display anything if that estimate is for less than a few seconds.
- However, this is probably unnecessary.
-
- @itemize
- @item
- @code{void announce_read_progress()}
-
- The kernel calls this regularly while reading game definitions.
- Interfaces running on slow machines should use this to indicate that
- everything is still working; for instance, the Mac interface animates
- a special cursor that indicates reading is taking place.
-
- @item
- @code{void announce_lengthy_process(char *msg)}
-
- The kernel calls this at the beginning of each synthesis. The argument
- is a readable string that the interface can show to players.
-
- @item
- @code{void announce_progress(int pctdone)}
-
- The kernel may call this at milestones within a synthesis.
- The number ranges from 0 to 100.
-
- @item
- @code{void finish_lengthy_process()}
-
- The kernel calls this at the end of a synthesis.
-
- @end itemize
-
- @subsection Feedback and Control
-
- The interface should provide visible feedback for every successful unit
- action initiated directly by the player, but it need not do so for failures,
- unless they are serious. It is better to prevent nonsensical input,
- for instance by disabling menus and control panel items. Simple interfaces
- such as for character terminals will have to relax these rules somewhat.
-
- Interfaces should enable/disable display of lighting conditions.
-
- @subsection Commands
-
- There is no single correct way to support direct player control over units.
- Although keyboard commands and mouse clicks are obvious choices,
- it would be very cool to allow a pen or mouse to sketch a movement plan,
- or to be able to give verbal orders...
-
- There is a common set of ASCII keyboard commands that are recommended
- for all @i{Xconq} interfaces that use a keyboard.
- These are defined in @code{kernel/cmd.def}.
- If you use these, @i{Xconq} players will be able to switch platforms
- and still use familiar commands. @code{cmd.def} defines a single character,
- a command name, a help string, and a function name,
- always in the form @code{do_*}.
- However, @code{cmd.def} does not specify arguments, return types,
- or behavior of those functions, so each interface must still define
- its own command lookup and calling conventions.
-
- Prefixed number args should almost always be repetitions.
-
- If already fully fueled, refuel commands should come back immediately.
-
- A quit cmd can always take a player out of the game, but player may have
- to agree to resign. Player can also declare willingness to quit or draw
- without actually doing so, then resolution requires that everybody agree.
- If quitting but others continuing on, also have option of being a
- spectator. Could have notion of "leaving game without declaring entire
- game a draw" for some players.
- Allow for a timeout and default vote in case some voters have disappeared
- mysteriously.
- Must never force a player to stay in.
- Add a notion of login/logout so a side can be inactive but untouchable,
- possibly freezes entire game if a side is inactive.
- 1. if one player or no scoring
- confirm, then shut player down
- if one player, then shut game down
- 2. if side is considered a sure win (how to tell? is effectively a win
- condition then) or all sides willing to draw
- confirm, take side out, declare a draw, shut player down
- 3. if all sides willing to quit
- take entire game down
- 4. ask about resigning - if yes,
- resign, close display, keep game running
- if no, ask if willing to quit and/or draw, send msg to other sides
- Kernel support limited to must_resign_to_quit(side), similar tests.
-
- @subsection Error Handling
-
- The interface must provide implementations of these error-handling
- functions:
-
- @itemize
- @item
- @code{void low_init_warning(str)}
-
- This is for undesirable but not necessarily
- wrong things that happen while setting up a game. For instance,
- if players start out too close or too far from each other, it will
- often affect the play of the game adversely, so the kernel issues
- a warning, therby giving the prospective players a chance to cancel
- the game and start over. The kernel's warning message should
- indicate any likely results of continuing on, so the players can
- decide whether or not to chance it.
-
- @item
- @code{low_init_error(str)}
-
- This function should indicate a serious and unrecoverable error
- during initialization. It should not return to its caller.
-
- @item
- @code{low_run_warning(str)}
-
- Warnings during the game are rare but not unknown.
- They are very often due to bugs in @code{Xconq}, so any
- occurrence should be investigated further. It is possible
- for some game designs to have latent flaws that may result
- in a warning.
- In any case, the interface should allow the players to continue
- on, to save their game and quit, by calling @code{save_the_game},
- or else quit without saving anything.
-
- @item
- @code{low_run_error(str)}
-
- In the worst case, @i{Xconq} can get into a situation, such as
- memory exhaustion, where there is no way to continue. The kernel
- will then call @code{run_error}, which should inform players that
- @i{Xconq} must shut itself down. They do get the option of saving
- the game, and the routine should call @code{save_game_state??} to
- do this safely. This routine should also not return to its caller.
-
- @item
- @code{printlisp(obj)}
-
- This is needed to print GDL objects to ``stdout'' or its equivalent.
-
- @end itemize
-
- @subsection Textual Displays
-
- Text can take a long time to read, and can be difficult to provide
- in multiple human languages. (What, you thought only English speakers
- played @i{Xconq}? Think again!)
- Therefore, text displays in the interfaces should be as minimal as
- possible, and derive from strings supplied in the game design,
- since they can be altered without rebuilding the entire program.
-
- (@i{Xconq} is not, at the moment, completely localizable,
- but that is a design goal.)
-
- @subsection Display Update
-
- Usually the interface's display is controlled by the player,
- but when @code{run_game} is executing, it will frequently change
- the state of an object in a way that needs to be reflected in the
- display immediately. Examples include units leaving or entering
- a cell, sides losing or winning, and so forth. The interface
- must define a set of callbacks that will be invoked by the kernel.
-
- @itemize
- @item
- @code{update_cell_display(side, x, y, rightnow)}
-
- [introduce area (radius or rect) update routines?]
-
- @item
- @code{update_side_display(side, side2, rightnow)}
-
- @item
- @code{update_unit_display(side, unit, rightnow)}
-
- @item
- @code{update_unit_acp_display(side, unit, rightnow)}
-
- @item
- @code{update_turn_display(side, rightnow)}
-
- @item
- @code{update_action_display(side, rightnow)}
-
- @item
- @code{update_action_result_display(side, unit, rslt, rightnow)}
-
- @item
- @code{update_fire_at_display(side, unit, unit2, m, rightnow)}
-
- @item
- @code{update_fire_at_display(side, unit, x, y, z, m, rightnow)}
-
- @item
- @code{update_event_display(side, hevt, rightnow)}
-
- @item
- @code{update_all_progress_displays(str, s)}
-
- @item
- @code{update_clock_display(side, rightnow)}
-
- @item
- @code{update_message_display(side, sender, str, rightnow)}
-
- @item
- @code{update_everything()}
-
- @end itemize
-
- Each of these routines has a flag indicating whether the change may be
- buffered or not.
- To ensure that buffered data is actually onscreen,
- the kernel may call @code{flush_display_buffers()},
- which the interface must define.
-
- @itemize
- @item
- @code{flush_display_buffers()}
-
- @end itemize
-
- These may or may not be called on reasonable sides, so the
- interface should always check first that @code{side} actually
- exists and has an active display.
- [If side has a "remote" display, then interface has to forward??
- No, because remote copy of game is synchronized and does own
- update_xxx calls more-or-less simultaneously]
-
- Note that this is as much as the kernel interests itself in displays.
- Map, list, etc drawing and redrawing are under the direct control
- of the interface code.
-
- @subsection Types of Windows and Panels
-
- @i{Xconq} is best with a window-style interface, either tiled
- or overlapping. Overlapping is more flexible, but also more
- complicated for players.
- In the following discussion, "window" will refer to a logically
- unified part of the display,
- which can be either a distinct window or merely a panel
- embedded in some larger window.
-
- The centerpiece window should be a map display.
- This will be the most-used window,
- since it will typically display more useful information
- than any other window.
- This means that it must also exhibit very good performance.
-
- When a game starts up, the map display should be centered
- on one of the player's units, preferably one close to the
- center of all the player's units.
-
- Another recommended window is a list of all the sides and where
- they stand in both the current turn and in the game as a whole.
- Each side's entry should include its name, a progress bar or
- other doneness indicator, and room for all the scores and scorekeepers
- that apply to that side.
-
- If possible, you should also implement
- some kind of "face" or group of faces/expressions for a side,
- so get a barbarian's face to repn a side instead of generic.
- Could have interface generate remarks/balloons if face clicked on,
- perhaps a reason for feelings, slogan, citation of agreement or broken
- agreement, etc.
- Need 5 faces for hostile, unfavorable, neutral, favorable, friendly/trusting.
-
- Overall status of side rules:
-
- all grayed: out of game
-
- grayed and x-ed out: lost
-
- ???: won
-
- Progress bar rules:
-
- missing: no units or no ai/no display
-
- grayed frame: no acting units
-
- empty solid frame: all acted
-
- part full, black: partly acted
-
- part full, gray: finished turn
-
- @subsection Imaging
-
- Imaging is the process of drawing pictorial representations.
- Not every interface needs it. For instance the curses interface
- is limited to drawing two ASCII characters for each cell,
- and its imaging code just has to choose which two to draw.
- However, full-color bitmapped displays need more attention
- to the process of getting an image onscreen.
-
- No graphical icon should be drawn smaller than about 8x8, unless it's
- a text character drawn in two contrasting colors.
-
- Interfaces should cache optimal displays for each mag, not search
- for best image each time.
-
- Could allow 1-n "display variants" for all images, and for each orientation of
- border and connection.
-
- Imaging variations can be randomly selected by UI,
- but must be maintained so redraws are consistent.
-
- Allow the 64 bord/conn combos as single images, also advantage
- that all will be drawn at once.
-
- Draw partial cells around edges of a window, to indicate that the world
- continues on in that direction.
-
- Interface needs to draw only the terrain (but including connections and
- borders) in edge cells.
-
- Could draw grid by blitting large light pattern over world, do by inverting
- so is easy to turn on/off. Do grids by changing hex size only in
- unpatterned color?
-
- Draw large hexagon or rect in unseen-color after clearing window to bg
- stipple (if unseen-color different). Polygon should be inside area
- covered by edge hexes, so unseen area more obvious.
- Make large unseen-pattern that includes question marks?
-
- If picture not defined for a game, use some sort of nondescript image
- instead of leaving blank. (small "no picture available" for instance,
- like in yearbooks)
-
- To display night, could invert everything (b/w) or do 25/50% black (color)
- (let game set, so some games could be all-black at night, nothing visible)
- (have day/night coverage for each utype?)
-
- To display elevation, use deep blue -> light gray -> dark brown progression,
- maybe also contour lines?
- To draw contour lines, for each hex, look at each adj hex. If on other
- side of contour's elev, compute interpolated point (in pixels) and save
- or draw a line to (one or both of the two) adj hex borders if they also
- have the contour line pass through. Guaranteed that line is part of
- overall contour line. Cheaper approach doesn't interpolate, just draws
- to midpoint of hex border (probably OK for small mags).
- Could maybe save contour lines once calculated (at each mag, lots of mem).
-
- @subsection Animation
-
- In addition to basic imaging, you can also support requests
- for the playing of animations or @i{movies}.
-
- The kernel just calls @code{schedule_movie} to create one,
- and then @code{play_movies} when it is time to run all the
- movies that have been scheduled. It is up to the interface
- to do something useful. Note that the kernel is not aware
- of the movies' timing, so it is better not to call @code{run_game}
- until all the movies have finished playing. (Yes, this would
- be a good future enhancement!)
-
- @itemize
-
- @item
- @code{schedule_movie(side, movie_type, args...)}
-
- @item
- @code{play_movies(sidemask)}
-
- Run all of the animations, sounds, etc that were scheduled
- previously, for the sides enabled in the side mask.
- It is allowable for the interface not to act on any user input
- while these are playing.
-
- @end itemize
-
- Several types of movies are predefined, so your interface can
- recognize them specially. These include @code{movie_miss},
- @code{movie_hit}, @code{movie_death}, which are scheduled
- for the appropriate outcomes of combat.
-
- @subsection Game Designer's Tools
-
- An interface is not required to provide any sort of online
- designing tools, or even to provide a way to enable the
- special design privileges. Nevertheless, minimal tools
- can be very helpful, and you will often find that they are
- helpful in debugging the rest of the interface, since you
- can use them to construct test cases at any time.
-
- A basic set of design tools should include a way to enable
- and disable designing for at least one side, a command to
- create units of a given type, and some sort of tool to set
- the terrain type at a given location. A full set would
- include ``painting'' tools for all area layers, including
- geographical features, materials, weather, side views,
- and so forth - about a dozen in all.
-
- A least one level of undo for designer actions is very
- desirable, although it may be hard to implement.
- A useful rule for layers is to save a layer's previous
- state at the beginning of each painting or other modification
- action, when the mouse button first goes down.
-
- The designer will often want to save only the part of the game
- being worked on, for instance only the units or only the terrain.
- The "save game" action should give designers a choice about
- what to save. For units particularly, the designer should be
- able to save only some properties of units. The most basic
- properties are type, location, side, and name/number.
- The unit id should not be saved by default, but should have
- its own option (not clear why).
-
- Note that because game modules are textual and can be
- moved easily from one system to another, it is entirely
- possible to use one @i{Xconq} (perhaps on a Mac) to design
- games to be played on a Unix box under X11, or vice versa.
- Transferring the imagery is more difficult, although there
- is some support for the process.
-
- @subsection Porting and Multiple Interfaces
-
- In theory, it is possible to compile multiple interfaces
- into a single @i{Xconq} program, but this would be hard at best.
- They would have to be multiplexed appropriately and not
- conflict anywhere in the address space.
- Sometimes this is intrinsically impossible;
- how could you compile the Mac and X interfaces into the same
- program, and would the result be a Mac application, a Unix program,
- or what?
-
- @subsection Useful Displays
-
- This is a collection of minor but useful displays that might be worth
- adding to an interface.
-
- A ``mouse over'' is a line or two of text that describes what the
- mouse/pointer is currently pointing at, and which updates automatically
- as the player moves the pointer around. This is better for high-bandwidth
- interfaces, since there may be a lot of updating involved. The volume
- can be reduced slightly by only redisplaying when the mouse moves, or,
- better, when what is being looked at changes. This is probably best done
- by recalculating the line of text and then comparing it to what has been
- drawn already, although if the display is very fast, you may not save much
- in drawing time. One approx 40-char lines covers basic info, such as
- terrain type and unit type; more detail may require multiple long lines.
-
- @subsection Useful Options
-
- A ``follow action'' option scrolls the screen to where the last event
- happened, such as combat. [etc]
-
- @subsection Debugging Aids
-
- @i{Xconq} is complicated enough that you can't expect to throw together
- a complete working interface over the weekend.
- Therefore, you should build some debugging aids into the interface.
- You can ifdef with the flag @code{DEBUGGING} so as to ensure the code
- won't be in final versions.
-
- Display unit id if closeups, toplines, etc, if debugging is on.
-
- @subsection Guidelines and Suggestions
-
- Although as the interface builder, you are free to make it work in any
- way you like, there are a number of basic things you should do.
- Some of these are general user interface principles, others are specific
- to @i{Xconq}, usually based on experiences with the existing interfaces.
- Applying some of these guidelines will require judicious balancing between
- consistency with the different version of @i{Xconq} and consistency with
- the system you're porting to.
-
- [following items should be better organized, moved in with relevant sections]
-
- Draw single selected unit in a stack larger.
-
- Draw single selected occupant in UR corner next to transport, when at
- mags that show both transport and occs.
-
- There should always be some sort of "what's happening now" display
- so player doesn't wonder about apparently dead machine.
-
- Image tool should report which type of resource is generating a
- given image, so can find which to hack on (report for selected image only).
-
- Interfaces should ensure stability of display choices
- if random possibilities, so need to cache local decisions about
- appearance of units if multiple images to choose from, choice of
- text messages, etc.
-
- Rules of Interaction:
- 1. Player can get to any unit in any mode.
- 2. Any player can prevent a turn from completing(/progressing?),
- unless a hard real limit is encountered.
- 3. All players see each others' general move/activity state, modes, etc.
- 4. Players can "nudge" each other.
- 5. Real time limits can be set for sides, turns, and games, both by players
- and by scenarios.
-
- Player should be able to click on a desired unit or image, and effectively
- say "take this", either grabs directly or else composes a task to approach
- and capture.
-
- Unit closeups should be laid out individually for each type, too much
- variability to make a single format reasonable.
-
- Add option where game design can specify use or avoidance of masks
- with unit icons.
-
- Player could escape a loss by saving a game, then discarding save.
- Mplayers could register suspicion when player saves then quits -
- "You're not trying to cheat, are you?" - but can't prevent this.
-
- All interfaces should be able to bring up an "Instructions" window
- that informs player(s) about the current game, includes xrefs to all
- game design info. Restrict help to generic and interface info only.
-
- Graph display should graphing of various useful values, such as amounts
- of units and materials over time, attitudes of sides, combat, etc.
- Maximal is timeline for all sides and units, usually too elaborate but
- allow tracking movement for some "important" units. Note that move
- actions may be recorded anyway.
-
- Make specialized dialog for agreements, put name on top, then scrolling list of
- terms, then signers, then random bits (public/secret, etc). Use for proposals
- also, so allow for "tentative" signers, desired signers who have not looked at
- agreement. Be able to display truth of each term, but need test to know when
- a side can know the truth of a term?
-
- Interfaces should have a ``wake up dummy'' button that can be used by players
- who have finished their turn, to prod other players not yet done.
-
- Commands that are irrelevant for a game ought to be grayed out in
- help displays, and error messages should identify as completely invalid
- (or just not do anything, a la grayed Mac menu shortcuts).
-
- Should be able to drag out a route and have unit follow it (user input
- of a complete task sequence).
-
- Hack formatting so that variable-width fonts usually work reasonably.
-
- Add xref buttons to various windows to go to other relevant windows and
- focus in.
-
- The current turn or date should be displayed prominently and be visible
- somewhere by default.
-
- Add some high-level verbs as commands ("assault Berlin", "bomb London until
- destroyed").
-
- Don't draw outline boxes at mags that would let them get outside the hex.
-
- If dating view data, allow it to gray out rather than disappear entirely.
- Could even have a "fade time" for unit images...
-
- Even if display is textual, use red text (and other colors) to indicate
- dangerous conditions.
-
- Next/prev unit controls should change map focus, even if screen
- unaffected.
-
- In general, ability to "select" a unit implies ability to examine,
- but not control. Control implies ability to select, however.
-
- Use a builtin color matching a color name if possible, otherwise
- use the imc definition.
-
- Connections may need to be drawn differently in each of the two hexes
- they involve, such as straits connecting to a sea.
- (what is this supposed to mean?)
-
- If cell cramped for space, show only one material type at a time,
- require redraw to show amounts of a different type.
-
- Draw time remaining both digitally and as hourglass, for all time
- limits in effect.
-
- Could tie map to follow a specified unit (or to flip there quickly
- a la SimAnt).
-
- Have a separate message window from notices, allow broadcasting w/o
- specific msg command? (a "talk" window)
-
- Redraw hexes exposed when a unit with a legend moves.
- Truncate or move legend if would overlap some other unit/legend.
-
- Put limits on the number of windows of each type, set up so will reuse
- windows, except for ones that are "staked down".
-
- Fix border removal so inter-hex boundary pixels are cleaned up also.
-
- Need a specialized window or display to check on current scores
- (showing actual situation vs what's still needed).
- (Show both scorekeepers actually in force, as well as the others.)
- Side display could also display scores relevant to that side.
-
- Every unit plan display should have a place to record notes and general
- info about the unit, add a slot to units also. Use in scenarios.
-
- Need a command for when a player can explicitly change the self-unit.
-
- Players should be able to rename any named object. The interface should
- also provide a button or control to run any namer that might be available
- to the unit.
-
- Be able to select unit number display indep of unit name display,
- and feature name display indep of unit names.
-
- Don't draw things that xform to 0 pixel areas,
- only draw the most important things if 1-4 pixels or so.
-
- If time/effort to do action is > length of game, then interface
- can disable that action permanently.
-
- Use moving bar or gray under black to indicate reserve/asleep units.
-
- @section Networking
-
- @i{Xconq} has been also been designed to allow for different kinds of
- networking strategies.
-
- The kernel/interface architecture can be exploited to build
- a true server/client @i{Xconq},
- by building an ``interface'' that manages IPC connections
- and calling this the server, and then writing separate interface
- programs that translate data at the other end of the IPC connection
- into something that a display could use.
- My previous attempt at this (ca 1989) was very slow and buggy,
- though, so this is not necessarily an easy thing to write.
- The chief problem is in keeping the client's view of thousands
- of interlinked objects (units, sides, cells, and so forth)
- consistent with the server.
- Most existing server/client games work by either restricting
- the state to a handful of objects,
- or by only handing the client display-prepared data
- rather than abstract data,
- or by reducing the update interval
- to minutes or hours.
-
- [When networking, all kernels must call with same values...]
-
- @section Miscellany
-
- @subsection Versioning Standards
-
- In version @var{7.x.y}, @var{x} should change only
- when some documented user-visible aspect of @i{Xconq} changes,
- whether in the interface or kernel.
- In particular, any additions to GDL, such as a new table or
- property, require a new @var{x} version.
- @var{y} is reserved for bug-fix releases, which can include
- the implementation of features that were documented but not
- actually made to work.
-
- @section Pitfalls
-
- This chapter would not be complete without some discussion of the traps
- awaiting the unwary hacker.
- The Absolute Number One Hazard in hacking @i{Xconq} is to introduce
- code that does not work for @emph{all} game designs.
- It is all too easy to assume that, for instance, unit speeds are always
- less than 20, or airbases can only be built by infantry, or that worlds
- are always randomly-generated.
- These sorts of assumptions have caused no end of problems.
- Code should test preconditions, especially for dynamically-allocated
- game-specified objects, and it should be tested using the various
- test scripts in the test directory.
-
- The number two pitfall is to not account for all the possible interfaces.
- Not all interfaces have a single ``current unit'' or map window,
- and some communicate with multiple players or over a network connection.
-
- You should not assume that your hack is generally valid until you have
- tested it against everything in the library and test directories.
- The @code{test} directory contains scripts that will be useful for this,
- at least to Unix hackers. See the @code{README} in that directory
- for more information.
-
- Another pitfall is to be sloppy about performance. An algorithm that works
- fine in a small world with two sides and 50 units may be painfully slow
- in a large game. Or, the algorithm may allocate too much working space
- and wind up exhausting memory (this has often happened).
- You should familiarize yourself with the algorithms already used in @i{Xconq},
- since they have already been debugged and tuned, and many have been written
- as generically useful code (see the area-scanning functions in @code{world.c}
- for instance).
-
- If your new feature is expensive, then define a global and compute its value
- only once, either at the start of the game or when it becomes relevant.
- Such a global should be named @code{any_<feature>}.
-
- Similarly, complicated tests on unit types or sides should be calculated
- once and cached in a dynamically-allocated array.
-
- @section Rationale and Future Directions
-
- This is where I justify what I've done, and not done.
-
- Please note that although @i{Xconq} has considerable power,
- its design was expressly limited to a particular class of two-dimensional
- board-like strategy games, and that playability is emphasized over
- generality. For instance, I avoided the temptation to include a
- general-purpose language, since it opens up many difficult issues
- and makes it much harder for game designers to produce a desired
- game (after all, if game designers wanted to use a general-purpose
- programming language, they could just write C code!). Similarly,
- full 3D, realtime maneuvering, continuous terrain, and other such goodies
- must await the truly ultimate game system.
-
- The real problem with a general-purpose language is that although
- everything is possible, nothing is easy. Many ``adventure game
- writing systems'' have fallen into this trap; they end up being
- poor reimplementations of standard programming languages, and the
- sole support for adventure gaming amounts to a small program
- skeleton and a few library functions. It would have been easier
- just to start with a pre-existing language and just write the
- skeleton and libraries!
-
- @i{Xconq}, on the other hand, provides extensive optimized support
- for random game setup, large numbers of units, game save/restore,
- computer opponents, and many other facets of a game.
- Game designers don't have to deal with
- the subleties of fractal terrain synthesis, or the ordering of
- terrain effects on units, or how to tell the computer opponents
- that airbases are sometimes good for refueling but never any
- good for transportation, or the myriad of other details that
- are wired into @i{Xconq}.
- In fact, a complete working game can be set up with less than
- a half-page of GDL.
-
- Even so, the current @i{Xconq} design allows for several layers
- of extensibility, as was described earlier in this chapter.
-
- There are also several major areas in which @i{Xconq}
- could be improved.
-
- Tables should be supplemented with general formulae, although
- such formulae will complicate AIs' analyses considerably,
- since tables are much easier to scan. Formula-based game
- definition would work much better with AIs that are coded
- specifically for the game and compiled in; this is more-or-less
- possible now, but there is not yet a good way to keep AIs
- from being used in games where they would be inappropriate
- (it might be amusing to have a panzer general AI attempting
- to play Gettysburg, but the coding would have to be careful
- not to try to index nonexistent unit types).
-
- Currently everything is based on a single area of a single world.
- This could be extended to multiple areas in the world, perhaps
- at different scales, as well as to multiple worlds.
-
- However, even with its limitations, @i{Xconq} has provided,
- and will continue to provide, many years of enjoyable playing,
- designing, and hacking. Go to it!
-
-